package nginx

import (
	cmd2 "CaptchaCluster/cmd"
	"CaptchaCluster/log"
	"CaptchaCluster/server/conf"
	"fmt"
	"github.com/shirou/gopsutil/process"
	"io/ioutil"
	"os"
	"strings"
	"sync"
	"time"
)

const nginxConfModule = `

#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;

events {
    worker_connections  1024;
}

http {
    #include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    #sendfile        on;
    #tcp_nopush      on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;
	upstream capthca {
{{serverList}}
	}

    server {
        listen       6033;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
           	proxy_set_header Host      $host;
			proxy_pass http://capthca;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

}

`

var (
	cmd   cmd2.Cmd
	mutex sync.Mutex
)

type NginxConf struct {
	Addr   string
	Weight int
}

// 启动nginx
func Start() {
	Stop()

	log.Release("start nginx")
	cmd.Start(1*time.Second, "cd ./nginx", "start nginx.exe")
	log.Release("finished starting nginx")
}

func nginxProcess() []*process.Process {
	processArr, err := process.Processes()
	if err != nil {
		return nil
	}

	var res []*process.Process
	for _, p := range processArr {
		if name, err := p.Name(); err == nil && name == "nginx.exe" {
			res = append(res, p)
		}
	}
	return res
}

// 停止nginx
func Stop() {
	nginxProcess := nginxProcess()
	if len(nginxProcess) == 0 {
		return
	}

	log.Release("quit nginx")
	// 结束正在运行的nginx
	cmd.Start(1*time.Second, "cd ./nginx", "nginx -s stop")

	var wg sync.WaitGroup
	wg.Add(len(nginxProcess))
	for _, p := range nginxProcess {
		go func(process *process.Process) {
			process.Kill()
			wg.Done()
		}(p)
	}
	wg.Wait()
	log.Release("quit nginx is complete")
}

func nginxRuning() bool {
	processArr, err := process.Processes()
	if err != nil {
		log.Error("get process error: %v", err)
		return false
	}

	for _, v := range processArr {
		if name, _ := v.Name(); name == "nginx.exe" {
			return true
		}
	}
	return false
}

// 重载配置
func Reload() {
	mutex.Lock()
	defer mutex.Unlock()

	if !nginxRuning() {
		Start()
	}

	common := []string{
		"cd ./nginx",
		"nginx -s reload",
	}
	log.Release("reload nginx")
	if _, err := cmd.Start(10*time.Second, common...); err != nil {
		log.Error("reload nginx error: %v", err)
	}
	log.Release("reload nginx is complete")
}

//生成配置
func generateConf(servers []NginxConf) string {
	var confStr string
	if len(servers) > 2 {
		confStr += "least_conn;\n"
	}

	for _, v := range servers {
		addr := strings.Split(v.Addr, ":")[0]
		confStr += fmt.Sprintf("\t\tserver %s:8889 weight=%d max_fails=%d fail_timeout=%ds;\n",
			addr, v.Weight, conf.Server.Nginx.MaxFails, conf.Server.Nginx.FailTimeout)
	}

	return strings.Replace(nginxConfModule, "{{serverList}}", confStr, 1)
}

const nginxConfPath = "./nginx/conf/nginx.conf"

// 写出配置
func WriteConf(servers []NginxConf) error {
	os.Remove(nginxConfPath)
	var confStr string
	if len(servers) == 0 {
		confStr = strings.Replace(nginxConfModule, "{{serverList}}", "\tserver 200.200.200.200:200 down;", 1)
	} else {
		confStr = generateConf(servers)
	}
	return ioutil.WriteFile(nginxConfPath, []byte(confStr), 0644)
}
